﻿using UnityEditor;
using UnityEditor.Experimental.GraphView;
using EditorPort = UnityEditor.Experimental.GraphView.Port;
namespace NodeEditor
{
    public static class GraphViewChangeUtility
    {
        public static GraphViewChange GraphViewChanged(this NodeView view, GraphViewChange graphViewChange)
        {
            if (graphViewChange.elementsToRemove != null)
            {
                graphViewChange.elementsToRemove.ForEach(e=>ElementsToRemove(view.tree, e));
            }
            if (graphViewChange.edgesToCreate != null)
            {
                graphViewChange.edgesToCreate.ForEach(edge => EdgesToCreate(view.tree, edge));
            }
            return graphViewChange;
        }

        static void ElementsToRemove(Tree tree, GraphElement elem)
        {
            var item = elem as NodeItem;
            if (item != null)
            {
                NodeRemove(tree, item);
            }

            var edge = elem as Edge;
            if (edge != null)
            {
                EdgeRemove(tree, edge);
            }
        }

        static void NodeRemove(Tree tree,NodeItem item)
        {
            tree.nodes.Remove(item.node);
            for (var i = 0; i < item.inputContainer.childCount; i++)
            {
                var port = item.inputContainer[i] as EditorPort;
                if (!port.connected)
                    continue;

                foreach (var connection in port.connections)
                {
                    var node = connection.output.node as NodeItem;
                    node.portDict[connection.output.viewDataKey].childs.Remove(port.viewDataKey);
                }
            }

            for (var i = 0; i < item.outputContainer.childCount; i++)
            {
                var port = item.outputContainer[i] as EditorPort;
                if (!port.connected)
                    continue;

                foreach (var connection in port.connections)
                {
                    var node = connection.input.node as NodeItem;
                    node.portDict[connection.input.viewDataKey].childs.Remove(port.viewDataKey);
                }
            }
            AssetDatabase.RemoveObjectFromAsset(item.node);
            AssetDatabase.SaveAssets();
        }

        static void EdgeRemove(Tree tree, Edge edge)
        {
            var inputNode = edge.input.node as NodeItem;
            var ouputNode = edge.output.node as NodeItem;
            var inputPort = edge.input;
            var outputPort = edge.output;
            inputNode.portDict[inputPort.viewDataKey].childs.Remove(outputPort.viewDataKey);
            ouputNode.portDict[outputPort.viewDataKey].childs.Remove(inputPort.viewDataKey);
            EditorUtility.SetDirty(tree);
        }

        static void EdgesToCreate(Tree tree,Edge edge)
        {
            var inputNode = edge.input.node as NodeItem;
            var ouputNode = edge.output.node as NodeItem;
            var inputPort = edge.input;
            var outputPort = edge.output;
            inputNode.portDict[inputPort.viewDataKey].childs.Add(outputPort.viewDataKey);
            ouputNode.portDict[outputPort.viewDataKey].childs.Add(inputPort.viewDataKey);
            EditorUtility.SetDirty(tree);
        }
    }
}
